10. Preventing Resource Leaks

Preventing Resource Leaks

In this section, you will:

  • Describe common kinds of resource leaks and how they can happen.
  • Use try/catch/finally to prevent resource leaks.
  • Apply try-with-resources and the Closeable interface to prevent resource leaks.
  • Prevent closing resources multiple times.

ND079 JPND C2 L02 A12 Preventing Resource Leaks

Why Should We Prevent Resource Leaks?

  • Leaving files open wastes memory and other system resources.
  • Most operating systems limit the number of files that can be open at one time, so, when you leave a file open after you're done using it, you're potentially depriving programs of the ability to open other files in the future.
  • If you are using a buffered writer and forget to close it, the buffered writes might never actually be written to disk.

Why it is important to close streams that operate on files?

SOLUTION:
  • To avoid wasting resources.
  • The operating system limits the number of open files.
  • To ensure the file has latest information.

try-catch-finally Example

try-catch-finally can be very useful for preventing resource leaks.

Writer writer;
try {
  writer = Files.newBufferedWriter(Path.of("test"));
  writer.write("Hello, world!");
} catch (IOException e) {
  e.printStackTrace();
} finally {
  if (writer != null) {
    try {
      writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

The code in the finally block is guaranteed to execute after the code in the try block, even if the try block returns a value or throws an exception. This code also has a catch block, but that is optional.

try-with-resources Example

try (Writer writer = Files.newBufferedWriter(Path.of("test"))) {
  writer.write("Hello, world!");
} catch (IOException e) {
  e.printStackTrace();
}

Java 7 introduced the try-with-resources syntax. This new syntax allows you to initialize your resources in parenthesis right before the start of the try block. Resources initialized in this way are guaranteed to be closed after the try block finishes executing.

Although try-with-resources has removed the need for the finally block in a lot of modern Java code, there are still some use cases where the finally block is useful.

By the way, you can initialize multiple resources in the same try statement, like this:

// Copy the contents of "foo" to "bar"
try (InputStream in   = Files.newInputStream(Path.of("foo"));
     OutputStream out = Files.newOutputStream(Path.of("bar"))) {
  out.write(in.readAllBytes());
}

Suppose you have a FileReader variable that points to a file. How can you be sure that the file is closed when you are done using it?

SOLUTION:
  • Call the `close()` method inside a `finally` block.
  • Using try-with-resources.

Closeable and AutoCloseable

Only Closeable or AutoCloseable objects can be used in the try statement.

Most of the I/O classes we've talked about, including Stream, Reader, Writer, InputStream, and OuptutStream, already implement the Closeable interface, whose close() method can throw an IOException.

AutoCloseable.close() does not throw IOException.

Closeable and AutoCloseable are just regular Java interfaces, which means you can write your own implmentations and then use them in a try-with-resources block!

Further Reading